[レポート][DAT427-NEW] Amazon Aurora DSQL とそのアーキテクチャを詳しく見る #AWSreInvent

[レポート][DAT427-NEW] Amazon Aurora DSQL とそのアーキテクチャを詳しく見る #AWSreInvent

Clock Icon2024.12.09

製造ビジネステクノロジー部の 田中孝明 です。
2日目のキーノートで発表されてから話題の Amazon Aurora DSQL について、Deep Dive するセッションがあったのでレポートします。

概要

Amazon Aurora DSQL は、Amazon の数十年にわたるイノベーションと卓越した運用を利用した新しいサーバーレス分散 SQL データベースです。 AWS 副社長兼 Distinguished Engineer の Marc Brooker が、Aurora DSQL を新しいアプリケーションや最高レベルの復元力を必要とするアプリケーションにとって理想的な選択肢にする設計と主要な革新的テクノロジーについて詳しく解説します。 Aurora DSQL のアクティブ/アクティブ アーキテクチャが、単一リージョンおよびマルチリージョンの復元力と事実上無制限のスケールをどのように実現するかを学びます。

Amazon Aurora DSQL is a new serverless, distributed SQL database that uses decades of Amazon innovation and operational excellence. Join Marc Brooker, AWS VP and Distinguished Engineer, as he dives into the design and key innovative technologies that make Aurora DSQL the ideal choice for new applications and applications which require the highest level of resiliency. Learn how active-active architecture in Aurora DSQL delivers single- and multi-Region resiliency and virtually unlimited scale.

セッション

https://www.youtube.com/watch?v=huGmR_mi5dQ

Active-active and multi-Region

Screenshot 2024-12-09 at 18.15.11

AZ を用意するのではなくリードレプリカの追加もいらない、マルチリージョンのアクティブアクティブ構成の冗長化になります。
DSQL は PostgreSQL と互換性があり、ほとんどの PostgreSQL を使ってるアプリは移行できるとのこと。

ACID

Screenshot 2024-12-09 at 18.32.07

長年のデータベースのテーマである ACID 特性についておさらいされました。

  • Atomicity(原子性)

    • トランザクションは完全に成功するか、完全に失敗するかという原則。
    • トランザクション内のすべての操作が成功した場合のみ、その結果がデータベースに反映。
    • 一方で1つでも失敗した場合、トランザクション全体が取り消されデータベースは変更されていない状態に戻る。
  • Consistency(一貫性)

    • トランザクションが成功した場合、データベースは始端状態から終端状態へと一貫した状態に移行する。
    • データベースの整合性ルール(制約や規則)を満たすことを意味する。
    • トランザクションが成功した場合、関連するすべてのデータは一貫した状態でなければならない。
  • Isolation(分離性)

    • 複数のトランザクションが同時に実行されている場合でも、それらの間でデータの競合が生じないようにする。
    • 分離性レベルは、トランザクション間の干渉を最小限に抑えるための仕組み。
    • 分離性レベルには、READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE などがある。
  • Durability(永続性)

    • トランザクションがコミットされた後、システムの障害(ハードウェア故障、電源切れなど)にもかかわらずその結果は永続的に保持されることを保証する。
    • データベースのログへの書き込みや、ディスクへのコミットが含まれる。

Atomic and Durable and Isolated and Scalable

Screenshot 2024-12-09 at 18.35.25

二つの行を追加するコミットを例にとられていました。(例では Dogs を二行追加)
書き込みログを追加するプリミティブな構成、このログサービスを Journal と呼ぶ。これは Amazon の中で 10 年間培われてきたログサービス。S3 / DynamoDB / Kinesis / Lambda などのサービスを強化する重要なインストラクチャーです。

Screenshot 2024-12-09 at 18.40.02

別のトランザクションが同じ行、ID に対してコミットしようとする時に別の分散層を利用して対処するとのこと。
Adjudicator は最近コミットされた他のトランザクションとの競合を探すのが役割のようです。

Screenshot 2024-12-09 at 18.43.44

Adjudicator に Journal に書き込んでも良いか問い合わせている。
長年培われてきた並列化や、フォールトトレラントにする様々なアイデアが組み込まれているとのこと。

Queryable and Scalable

Screenshot 2024-12-09 at 18.47.56

Journal に書き込まれている書き込みログから情報を引っ張ってくるのはパフォーマンス的に現実的ではない。そこでストレージエンジンが登場し、ストレージエンジンはデータの一部を抽出する効率的な方法を提供している。ただしこの層は耐久性や分散などは担当していないとのこと。

Screenshot 2024-12-09 at 18.51.53

ストレージ層と Query Processor 層を分離し、それぞれの往復回数を大幅に削減している。
複雑なトランザクションを例にとると、操作内でアプリケーションに返す必要がありこれが分散データベースの実装を難しくしている。

Router

Screenshot 2024-12-09 at 18.59.29

AWS Lambda をスケーラブルにしている仕組みである Firecracker という VVM が Query Processor にも利用されているとのこと。

Isolation of Read

Screenshot 2024-12-09 at 19.02.54

Query Processor は独立しており、互いに完全に隔離されている。読み取りは全てポイントであることに注目する。
この時間の取得は Atomic clocks によって行われている。
Query Processor はトランザクションが開始された時に Atomic clocks からタイムスタンプを取得する。これらはトランザクションの間は一定の値で問い合わせられる。

Screenshot 2024-12-09 at 19.08.53

このタイムスタンプがどう作用するのかをストレージに書き込みする時を例に説明。データへの問い合わせはタイムスタンプで認識している。

この時にデータベースへのロックは行わないとのこと。
このタイムスタンプを見て、前のタイムスタンプのものがあれば最も一貫性のあるバージョンに確実に適用されるまで待たれている。

Architect

Screenshot 2024-12-09 at 19.12.51

ここまではそれぞれの層を分離する話でした。大事なことですが各レイヤーはリクエストに応じて水平方向に Scale するとのこと。

Amazon Aurora で行ったことは PostgreSQL のストレージ層、レプリケーション層、データ整合性層の分離だった。

DSQL で行ったのはそれをさらに強化し、データベースのすべての機能を完全に分離するまでチャレンジされていた。

PostgreSQL の操作はすべて Query Processor 層で行われているとのこと。

Reads and Writes

Screenshot 2024-12-09 at 19.19.30

いくつかの読み取りと書き込みの例で、リソースは Router を通り、Query Processor に流れ、Query Processor は必要なストレージへデータを取得するように作用する。

Screenshot 2024-12-09 at 19.24.05

最終的に書き込みをする場合の流れの説明がされてた。
3つある Adjudicator のうち、2つの Adjudicator に必要なデータがある場合、2つに問い合わせている流れを取られていた。
そのうちの 1つの Adjudicator のみが Journal に入ってデータを取得することで原子性を保証する。
そこからキーを取得してストレージに適用させている。

Deep dive: Isolation

Screenshot 2024-12-09 at 19.30.27

トランザクションの開始時刻を、Amazon Time Sync Service でシステム全体で厳密なタイムスタンプを取得している。

Screenshot 2024-12-09 at 19.32.34

調整の必要がないこのコミットによって、スケーラビリティとレイテンシーが大幅に最適化されるとのこと。

Screenshot 2024-12-09 at 19.34.39

コミットの際に Optimistic Concurrency Control が使用されているとのこと。

同時に発生した可能性のあるトランザクションを見た時に分離ルールを尊重しながらトランザクションをコミットできるか示している。

Screenshot 2024-12-09 at 19.39.44

利用している分離レベルは Strong Snapshot Isolation とのこと。

トランザクションが開始された時点でデータベースのスナップショットが作成され、そのスナップショットに基づいてトランザクションが実行される。読み取りトランザクションはロックに阻まれる可能性が低くなり、トランザクションの待機時間が短縮されるとのこと。

Screenshot 2024-12-09 at 19.43.36

この例のコミットは SERIALIZABLE な分離レベルではコミットされない。このコミットは同じ行への操作のため選択時にロックする。楽観的ロックであれば両方のコミットすることはできない。これはシリアルデータベースのシリアル化で重要なポイントであり、読み取りを実行するだけではトランザクションが中止される可能性がある。

Screenshot 2024-12-09 at 19.48.22

すべての読み取りは T start で実施され、データベースに書き込むコミット時に T commit というタイムスタンプを選択する。他のトランザクションが同じキーに書き込まれない限りトランザクションがコミットできることを選択している。

Screenshot 2024-12-09 at 19.51.50

Query Processor が Adjudicator に自分が書き込みたいキーがあることを伝える。他のトランザクションが同じキーに書き込んでいない時に T commit を選択しこの時間と共に Journal に書き込む。

Deep dive: Closs-Region

Screenshot 2024-12-09 at 19.56.46

マルチリージョンのパフォーマンス改善はリージョン感のラウンドトリップを最適化すること。ただしどんなに頑張っても大陸間横断などは限界がある。

Screenshot 2024-12-09 at 19.59.09

クエリをローカルのみを考慮すればいい点と、マルチリージョンを考慮する必要がある点に分離する。
コミットについては、マルチリージョンを考慮する必要がある点がある。一つのリージョンで致命的な障害が発生した時でもデータの耐久性を確保するために複数のリージョンにデータをコピーする必要がある。これを確保するためには少なくとも複数のリージョンにデータを書く以外はないとのこと。

Screenshot 2024-12-09 at 20.03.37

読み取り専用トランザクションに対して何の操作も行わないのでいつでもローカルでコミットできる。キーが書かれていないので Adjudicator に問い合わせることもない。コミット時に一回、読み取り書き込みトランザクションに対してのみ行われるとのこと。

Screenshot 2024-12-09 at 20.08.22

重要な設計目標は高速フェールオーバーを最適化するだった。特定のキーを操作する唯一の層に関してはリーダーシップ交代による Adjudicator 変更を可能な限り迅速に変更できるようにした。あくまでソフトな状態を維持し、長期間存在するようなハードな状態を持たないように設計しているとのこと。

Screenshot 2024-12-09 at 20.13.15

3つのリージョンにまたがる構成を例に取られてた。図では 2つは Active な構成で、一つのリージョンは Journal のみの監視リージョンを持っている。広域にまたがときは 3つのリージョンの中間に監視用の構成を置くのはレイテンシーを最適化することになるとのこと。

Screenshot 2024-12-09 at 20.17.11

特定のリージョン(図ではリージョンC)で障害が発生したとき、Adjudicator は無事なリージョンへ全員移動するようになっている。
障害の起きたリージョンでは読み込み書き込みトランザクションが実行できなくなるが Route 53 などのヘルスチェックで無事なリージョンへのトラフィックを流すなどの対応をすれば良いとのこと。

Implementation quality

実装の正しさに対するユーザーへの信頼性を高めるために下した決断をいくつか紹介。

Screenshot 2024-12-09 at 20.23.35

言語は Rust を採用しているとのこと。選定理由としてメモリの安全性が確保されて、素晴らしいパフォーマンスに満足しているとのこと。同様のパフォーマンス特性を持ってる言語では回避するのが難しい安定性とセキュリティのバグを全体で回避できることも大きいとのこと。

Screenshot 2024-12-09 at 20.25.57

分散システムのテストで難しいところはアーキテクチャの特定の部分が信頼できないような不定な期間(クロックが信頼できない期間など)にネットワーク障害が発生した時のテストをすることだったとのこと。

ビルド時にユニットテストを生成し、これによって巨大なマルチリージョン分散データベースのテストを実現しているとのこと。※こちらは詳細を知りたいですね。

Screenshot 2024-12-09 at 20.31.41

何十億もの固有の SQL トランザクションを生成し、その後続仕様の動作や PostgreSQL の動作と照らし合わせてチェックできるツールをいくつか構築した。
今まで紹介したツールの一部については今後 OSS で公開する予定とのこと。

Screenshot 2024-12-09 at 20.35.36

数学的に厳密に意味付けられた言語を用いて設計書を記述し、システムが要求等を満たしているかなど論理的に推論しているとのこと。
長年 AWS でも利用されてきた手法で、ある程度具体的に表現することができるようにあっており、特定の行やコードの特定の実装の動作について推論できるようになっているとのこと。

Screenshot 2024-12-09 at 20.37.27

Runtime Monitoring についての詳細は後ほど公開予定とのこと。これによってアプリケーションのログを取得し、これをプロトコルを作成した時の仕様と比較してチェックしているとのこと。

最後に

2日目のキーノートの衝撃発表から話題の DSQL ですが、ここまで詳細に概念を話されたのは面白かったです。DSQL についてはMarc Brooker さんのブログ でも語られてきているので今後も内部実装を追っていきたいと思います。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.